package uw10.app.display;

import uw10.app.data.Event;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class EventSelectView extends View implements TweenHandler, OnTouchListener
{
	public Context context;
	
	private EventSelectListener listener;

	private EventIconRenderer eir;
	private Event[] events;
	
	private Bitmap[] cache;
	
	private volatile boolean ready;
	
	private int capacity;
	
	private float targetScroll;
	private volatile float scroll;
	
	private int oldCacheIndex;
	private volatile int cacheIndex;
	private float maxMove;
	
	private Bitmap slider;
	private float sliderPos;
	private volatile int sliderIndex;
	
	private boolean hasSlider;
	
	private float touchX;
	private boolean touch;
	
	private TweenRunnable tweenRunnable;
	
	public EventSelectView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		this.context = context;
		setOnTouchListener(this);
		
		tweenRunnable = new TweenRunnable(this, 50);
	}
	
	public void setup(int capacity, EventIconRenderer eir, Bitmap slider)
	{
		this.eir = eir;
		this.capacity = capacity;
		this.slider = slider;
		hasSlider = false;
		
		cacheIndex = 0;
		
		cache = new Bitmap[capacity];
		for (int i = 0; i < cache.length; i++)
		{
			cache[i] = Bitmap.createBitmap(64, 64, Config.ARGB_8888);
		}
	}
	
	public void setListener(EventSelectListener listener)
	{
		this.listener = listener;
	}
	
	private void selectEvent(Event e)
	{
		if (listener != null) listener.onEventSelected(e);
	}
	
	public void setEvents(Event[] events)
	{
		this.events = events;
		for (int i = 0; i < cache.length; i++)
		{
			eir.render(cache[i], events[i]);
		}
		ready = true;
		this.invalidate();
	}
	
	public synchronized void onDraw(Canvas c)
	{
		if (ready)
		{
			if (cacheIndex != oldCacheIndex)
			{
				updateCache();
			}
			
			Rect tRect = new Rect();
			int w = getWidth() / (capacity - 1);
			int offset = (int) (-(scroll % 1) * w);
			for (int i = 0; i < capacity; i++)
			{
				tRect.set(offset + w * i, 0, offset + w * (i + 1), getHeight());
				c.drawBitmap(cache[i], null, tRect, null);
			}
			
			if (hasSlider)
			{
				tRect.set((int)(offset + w * (sliderPos - cacheIndex)), 0 , (int)(offset + w * (sliderPos + 1 - cacheIndex)), getHeight());
				c.drawBitmap(slider, null, tRect, null);
			}
		}
	}
	
	public void updateCache()
	{
		if (cacheIndex < oldCacheIndex)
		{
			for (int i = cacheIndex + capacity - 1; i >= oldCacheIndex; i--)
			{
				Bitmap temp = cache[i - cacheIndex];
				cache[i - cacheIndex] = cache[i - oldCacheIndex];
				cache[i - oldCacheIndex] = temp;
			}
			
			int redo = oldCacheIndex - cacheIndex;
			if (redo > capacity) redo = capacity;
			for (int i = 0; i < redo; i++)
			{
				eir.render(cache[i], events[cacheIndex + i]);
			}
		}
		else if (cacheIndex > oldCacheIndex)
		{
			for (int i = cacheIndex; i < oldCacheIndex + capacity; i++)
			{
				Bitmap temp = cache[i - cacheIndex];
				cache[i - cacheIndex] = cache[i - oldCacheIndex];
				cache[i - oldCacheIndex] = temp;
			}
			
			int redo = cacheIndex - oldCacheIndex;
			if (redo > capacity) redo = capacity;
			for (int i = capacity - redo; i < capacity; i++)
			{
				eir.render(cache[i], events[cacheIndex + i]);
			}
		}
		
		oldCacheIndex = cacheIndex;
	}
	
	public synchronized boolean doTweens()
	{		
		maxMove += 0.01f;
		if (maxMove > 0.2f) maxMove = 0.2f;
		
		float move = (targetScroll - scroll) * 0.1f;
		if (move > maxMove) move = maxMove;
		else if (move < -maxMove) move = -maxMove;
		scroll += move;
		cacheIndex = (int)scroll;
		
		boolean scrollFinished = false;
		if ((scroll - targetScroll < 0.05f && scroll - targetScroll > -0.05f))
		{
			maxMove = 0;
			scrollFinished = true;
		}
		
		if (touch)
		{
			sliderIndex = (int)(touchX * (capacity - 1) + scroll);
			if (!hasSlider)
			{
				sliderPos = sliderIndex;
				hasSlider = true;
			}
		}
		
		move = (sliderIndex - sliderPos) * 0.5f;
		if (move > 0.3f) move = 0.3f;
		else if (move < -0.3f) move = -0.3f;
		sliderPos += move;
		
		boolean sliderFinished = false;
		if ((sliderPos - sliderIndex < 0.05f && sliderPos - sliderIndex > -0.05f))
		{
			sliderFinished = true;
		}

		postInvalidate();
		
		return (!scrollFinished || !sliderFinished);
	}

	public synchronized boolean onTouch(View view, MotionEvent e)
	{
		if (e.getAction() == MotionEvent.ACTION_DOWN)
		{
			touch = true;
			touchX = e.getX() / getWidth();
			targetScroll = touchX * (float)(events.length) - ((capacity - 1) / 2.0f);
			if (targetScroll < 0) targetScroll = 0;
			if (targetScroll > events.length-capacity) targetScroll = events.length-capacity;
			tweenRunnable.doTweens();
		}
		if (e.getAction() == MotionEvent.ACTION_MOVE)
		{
			touchX = e.getX() / getWidth();
			targetScroll = touchX * (float)(events.length) - ((capacity - 1) / 2.0f);
			if (targetScroll < 0) targetScroll = 0;
			if (targetScroll > events.length-capacity) targetScroll = events.length-capacity;
			tweenRunnable.doTweens();
		}
		else if (e.getAction() == MotionEvent.ACTION_UP)
		{
			touch = false;
			touchX = e.getX() / getWidth();
			sliderIndex = (int)(touchX * (capacity - 1) + scroll);
			targetScroll = ((float)sliderIndex / events.length) * (float)(events.length) - ((capacity - 1) / 2.0f);
			if (targetScroll < 0) targetScroll = 0;
			if (targetScroll > events.length-capacity) targetScroll = events.length-capacity;
			
			if (!hasSlider)
			{
				sliderPos = sliderIndex;
				hasSlider = true;
			}
			
			tweenRunnable.doTweens();
			selectEvent(events[sliderIndex]);
		}
		return true;
	}
}
